from django.core.management.base import BaseCommand
from spider.tasks import crawl_douban_movies
from django.utils import timezone
from spider.utils.redis_utils import RedisClient
import time
from kombu.exceptions import OperationalError
import traceback
class Command(BaseCommand):
    help = '爬取豆瓣电影数据'
    def add_arguments(self, parser):
        parser.add_argument(
            '--force',
            action='store_true',
            help='强制重新爬取，即使有任务正在运行',
        )
        parser.add_argument(
            '--sync',
            action='store_true',
            dest='sync_mode',
            help='同步执行爬虫任务（不使用Celery）',
        )
    def handle(self, *args, **options):
        self.stdout.write('开始爬取豆瓣电影数据...')
        
        try:
            # 检查Redis连接
            redis_client = RedisClient()
            if not redis_client.set_key('test_connection', 'test', expire=10):
                self.stdout.write(self.style.ERROR('无法连接到Redis服务器，请确保Redis服务已启动'))
                return
            
            # 检查是否有任务正在运行
            if not options['force'] and redis_client.exists_key('crawling_status'):
                self.stdout.write(self.style.WARNING('已有爬虫任务正在运行，使用 --force 参数强制重新爬取'))
                return
            
            if options.get('sync_mode'):
                # 同步执行爬虫任务
                self.stdout.write('使用同步模式执行爬虫任务...')
                
                # 如果是强制模式，清除所有相关状态
                if options['force']:
                    redis_client.delete_key('crawling_status')
                    redis_client.delete_key('crawl_progress')
                    redis_client.delete_key('last_crawl_error')
                    self.stdout.write('已清除之前的爬取状态')
                
                try:
                    # 添加更多的日志输出
                    self.stdout.write('开始执行爬虫任务...')
                    result = crawl_douban_movies(sync_mode=True)
                    self.stdout.write('爬虫任务执行完成')
                    
                    if result:
                        self.stdout.write(self.style.SUCCESS('爬取成功！'))
                    else:
                        # 获取详细的错误信息
                        error_message = redis_client.get_key('last_crawl_error')
                        if error_message:
                            self.stdout.write(self.style.ERROR(f'爬取失败！错误信息: {error_message}'))
                        else:
                            self.stdout.write(self.style.ERROR('爬取失败！未知错误'))
                except Exception as e:
                    self.stdout.write(self.style.ERROR(f'爬虫任务执行出错: {str(e)}'))
                    # 添加更详细的错误信息
                    self.stdout.write(self.style.ERROR(f'错误详情:\n{traceback.format_exc()}'))
                finally:
                    # 清除爬取状态
                    redis_client.delete_key('crawling_status')
                    redis_client.delete_key('crawl_progress')
                return
            
            # 异步执行爬虫任务
            try:
                task = crawl_douban_movies.delay()
                self.stdout.write(f'任务已启动，任务ID: {task.id}')
            except OperationalError:
                self.stdout.write(self.style.ERROR('无法连接到Celery，请确保Celery worker已启动'))
                self.stdout.write('请运行: celery -A douban worker -l info')
                self.stdout.write('或者使用 --sync 参数同步执行任务')
                return
            
            self.stdout.write('正在等待任务完成...')
            
            # 等待任务完成并显示进度
            while True:
                try:
                    # 获取任务状态
                    task_status = task.status
                    progress = redis_client.get_key('crawl_progress')
                    
                    if task_status == 'SUCCESS':
                        self.stdout.write(self.style.SUCCESS('爬取成功！'))
                        break
                    elif task_status == 'FAILURE':
                        # 获取详细的错误信息
                        error_message = redis_client.get_key('last_crawl_error')
                        if error_message:
                            self.stdout.write(self.style.ERROR(f'爬取失败！错误信息: {error_message}'))
                        else:
                            self.stdout.write(self.style.ERROR('爬取失败！未知错误'))
                        break
                    elif task_status == 'PROGRESS' and progress:
                        # 显示进度信息
                        self.stdout.write(
                            f'进度: {progress["percentage"]}% '
                           f'({progress["current_page"]}/{progress["total_pages"]}页) '
                            f'已爬取 {progress["movies_count"]} 部电影 '
                            f'状态: {progress["status"]}'
                        )
                    
                    # 等待一段时间再检查
                    time.sleep(2)
                except Exception as e:
                    self.stdout.write(self.style.ERROR(f'获取任务状态时出错: {str(e)}'))
                    self.stdout.write(self.style.ERROR(f'错误详情:\n{traceback.format_exc()}'))
                    break
                    
        except Exception as e:
            self.stdout.write(self.style.ERROR(f'执行命令时出错: {str(e)}'))
            self.stdout.write(self.style.ERROR(f'错误详情:\n{traceback.format_exc()}'))
        finally:
            # 确保在任何情况下都清除爬取状态
            try:
                redis_client.delete_key('crawling_status')
                redis_client.delete_key('crawl_progress')
            except:
                pass